﻿#region 참조 네임스페이스

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;

#endregion

namespace Skying.Drawing
{
	/// <summary>
	/// 디스플레이되고 있는 화면에 대한 이미지 스냅샵을 얻기 위한 인터페이스를 제공한다.
	/// </summary>
	public static class ScreenCapturing
	{
		#region 상수

		/// <summary>
		/// 디스플레이에 대한 시스템 명칭 포맷 상수를 나타낸다.
		/// </summary>
		private const string _DISPLAY_NAME_FORMAT = "DISPLAY{0}";

		#endregion

		#region 전체 화면

		/// <summary>
		/// 디스플레이되고 있는 화면의 전체 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <remarks>
		/// <para>화면의 전체 영역은 모든 디스플레이의 가상 영역을 포함한다.</para>
		/// </remarks>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CaptureAllToFile(string fileName, ImageFormat imageFormat, float ratio = 1.0f)
		{
			int destinationWidth = (int)(SystemInformation.VirtualScreen.Width * ratio);
			int destinationHeight = (int)(SystemInformation.VirtualScreen.Height * ratio);

			CaptureToFile(fileName, imageFormat, SystemInformation.VirtualScreen, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 전체 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <remarks>
		/// <para>화면의 전체 영역은 모든 디스플레이의 가상 영역을 포함한다.</para>
		/// </remarks>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		public static void CaptureAllToFile(string fileName, ImageFormat imageFormat, int destinationWidth, int destinationHeight)
		{
			CaptureToFile(fileName, imageFormat, SystemInformation.VirtualScreen, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 전체 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <remarks>
		/// <para>화면의 전체 영역은 모든 디스플레이의 가상 영역을 포함한다.</para>
		/// </remarks>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureAllToStream(ImageFormat imageFormat, float ratio = 1.0f)
		{
			int destinationWidth = (int)(SystemInformation.VirtualScreen.Width * ratio);
			int destinationHeight = (int)(SystemInformation.VirtualScreen.Height * ratio);

			return CaptureToStream(imageFormat, SystemInformation.VirtualScreen, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 전체 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <remarks>
		/// <para>화면의 전체 영역은 모든 디스플레이의 가상 영역을 포함한다.</para>
		/// </remarks>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureAllToStream(ImageFormat imageFormat, int destinationWidth, int destinationHeight)
		{
			return CaptureToStream(imageFormat, SystemInformation.VirtualScreen, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 전체 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <remarks>
		/// <para>화면의 전체 영역은 모든 디스플레이의 가상 영역을 포함한다.</para>
		/// </remarks>
		public static void CaptureAllToClipboard(float ratio = 1.0f)
		{
			int destinationWidth = (int)(SystemInformation.VirtualScreen.Width * ratio);
			int destinationHeight = (int)(SystemInformation.VirtualScreen.Height * ratio);

			CaptureToClipboard(SystemInformation.VirtualScreen, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 전체 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		public static void CaptureAllToClipboard(int destinationWidth, int destinationHeight)
		{
			CaptureToClipboard(SystemInformation.VirtualScreen, destinationWidth, destinationHeight);
		}

		#endregion

		#region 디스플레이

		/// <summary>
		/// 디스플레이되고 있는 화면 중 일부 디스플레이의 화면 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="screenNumber">캡쳐할 디스플레이의 번호를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CaptureScreenToFile(string fileName, ImageFormat imageFormat, int screenNumber, float ratio = 1.0f)
		{
			Screen screen = Screen.AllScreens.SingleOrDefault(t => t.DeviceName.Contains(string.Format(_DISPLAY_NAME_FORMAT, screenNumber)));

			if (screen == null)
			{
				screen = Screen.PrimaryScreen;
			}

			CaptureToFile(fileName, imageFormat, screen.WorkingArea, ratio);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면 중 일부 디스플레이의 화면 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="screenNumber">캡쳐할 디스플레이의 번호를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CaptureScreenToStream(ImageFormat imageFormat, int screenNumber, float ratio = 1.0f)
		{
			Screen screen = Screen.AllScreens.SingleOrDefault(t => t.DeviceName.Contains(string.Format(_DISPLAY_NAME_FORMAT, screenNumber)));

			if (screen == null)
			{
				screen = Screen.PrimaryScreen;
			}

			CaptureToStream(imageFormat, screen.WorkingArea, ratio);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면 중 일부 디스플레이의 화면 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="screenNumber">캡쳐할 디스플레이의 번호를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CatpureScreenToClipboard(int screenNumber, float ratio = 1.0f)
		{
			Screen screen = Screen.AllScreens.SingleOrDefault(t => t.DeviceName.Contains(string.Format(_DISPLAY_NAME_FORMAT, screenNumber)));

			if (screen == null)
			{
				screen = Screen.PrimaryScreen;
			}

			CaptureToClipboard(screen.WorkingArea, ratio);
		}

		#endregion

		#region 스트림 출력

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다. 파일의 확장자는 <see cref="fileName"/> 인자에서 무엇이 설정되든 <see cref="System.Drawing.Imaging.ImageFormat"/>에 의해 결정된다.</param>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CaptureToFile(string fileName, ImageFormat imageFormat, Rectangle sourceRectangle, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceRectangle.Width * ratio);
			int destinationHeight = (int)(sourceRectangle.Height * ratio);

			CaptureToFile(fileName, imageFormat, sourceRectangle, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다. 파일의 확장자는 <see cref="fileName"/> 인자에서 무엇이 설정되든 <see cref="System.Drawing.Imaging.ImageFormat"/>에 의해 결정된다.</param>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="destinationSize">반환되는 비트맵의 크기를 설정한다.</param>
		public static void CaptureToFile(string fileName, ImageFormat imageFormat, Rectangle sourceRectangle, Size destinationSize)
		{
			CaptureToFile(fileName, imageFormat, sourceRectangle, destinationSize.Width, destinationSize.Height);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다. 파일의 확장자는 <see cref="fileName"/> 인자에서 무엇이 설정되든 <see cref="System.Drawing.Imaging.ImageFormat"/>에 의해 결정된다.</param>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		public static void CaptureToFile(string fileName, ImageFormat imageFormat, Rectangle sourceRectangle, int destinationWidth, int destinationHeight)
		{
			CaptureToFile(fileName, imageFormat, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다. 파일의 확장자는 <see cref="fileName"/> 인자에서 무엇이 설정되든 <see cref="System.Drawing.Imaging.ImageFormat"/>에 의해 결정된다.</param>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CaptureToFile(string fileName, ImageFormat imageFormat, int sourceX, int sourceY, int sourceWidth, int sourceHeight, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceWidth * ratio);
			int destinationHeight = (int)(sourceHeight * ratio);

			CaptureToFile(fileName, imageFormat, sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 특정 경로에 저장한다.
		/// </summary>
		/// <param name="fileName">캡쳐된 이미지 스냅샷을 저장할 경로를 설정한다.</param>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다. 파일의 확장자는 <see cref="fileName"/> 인자에서 무엇이 설정되든 <see cref="System.Drawing.Imaging.ImageFormat"/>에 의해 결정된다.</param>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		public static void CaptureToFile(string fileName, ImageFormat imageFormat, int sourceX, int sourceY, int sourceWidth, int sourceHeight, int destinationWidth, int destinationHeight)
		{
			Bitmap bitmap = Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight);

			try
			{
				FileInfo fileInfo = new FileInfo(fileName);

				if (fileInfo.Extension.Length > 0)
				{
					fileName = fileName.Replace(fileInfo.Extension, string.Format(".{0}", imageFormat.ToString().ToLower()));
				}
				else
				{
					fileName += string.Format(".{0}", imageFormat.ToString().ToLower());
				}

				using (FileStream fileStream = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.None))
				{
					bitmap.Save(fileStream, imageFormat);
				}
			}
			catch (Exception error)
			{
				throw error;
			}
			finally
			{
				if (bitmap != null)
				{
					bitmap.Dispose();
				}
			}
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureToStream(ImageFormat imageFormat, Rectangle sourceRectangle, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceRectangle.Width * ratio);
			int destinationHeight = (int)(sourceRectangle.Height * ratio);

			return CaptureToStream(imageFormat, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="destinationSize">반환되는 비트맵의 크기를 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureToStream(ImageFormat imageFormat, Rectangle sourceRectangle, Size destinationSize)
		{
			return CaptureToStream(imageFormat, sourceRectangle, destinationSize.Width, destinationSize.Height);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureToStream(ImageFormat imageFormat, Rectangle sourceRectangle, int destinationWidth, int destinationHeight)
		{
			return CaptureToStream(imageFormat, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureToStream(ImageFormat imageFormat, int sourceX, int sourceY, int sourceWidth, int sourceHeight, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceWidth * ratio);
			int destinationHeight = (int)(sourceHeight * ratio);

			return CaptureToStream(imageFormat, sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 <see cref="System.IO.Stream"/>으로 가져온다.
		/// </summary>
		/// <param name="imageFormat">캡쳐된 이미지 스냅샷에 대한 이미지 파일 형식을 설정한다.</param>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷의 <see cref="System.IO.Stream"/>이 반환된다.</returns>
		public static Stream CaptureToStream(ImageFormat imageFormat, int sourceX, int sourceY, int sourceWidth, int sourceHeight, int destinationWidth, int destinationHeight)
		{
			Stream stream = new MemoryStream();
			Bitmap bitmap = Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight);

			try
			{
				bitmap.Save(stream, imageFormat);
			}
			catch (Exception error)
			{
				throw error;
			}
			finally
			{
				if (bitmap != null)
				{
					bitmap.Dispose();
				}
			}

			return stream;
		}

		#endregion

		#region 클립보드 출력

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		public static void CaptureToClipboard(Rectangle sourceRectangle, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceRectangle.Width * ratio);
			int destinationHeight = (int)(sourceRectangle.Height * ratio);

			Clipboard.SetImage(Capture(sourceRectangle, destinationWidth, destinationHeight));
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="destinationSize">반환되는 비트맵의 크기를 설정한다.</param>
		public static void CaptureToClipboard(Rectangle sourceRectangle, Size destinationSize)
		{
			Clipboard.SetImage(Capture(sourceRectangle, destinationSize.Width, destinationSize.Height));
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		public static void CaptureToClipboard(Rectangle sourceRectangle, int destinationWidth, int destinationHeight)
		{
			Clipboard.SetImage(Capture(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth, destinationHeight));
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		public static void CaptureToClipboard(int sourceX, int sourceY, int sourceWidth, int sourceHeight, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceWidth * ratio);
			int destinationHeight = (int)(sourceHeight * ratio);

			Clipboard.SetImage(Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight));
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대한 이미지 스냅샷을 클립보드로 복사한다.
		/// </summary>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		public static void CaptureToClipboard(int sourceX, int sourceY, int sourceWidth, int sourceHeight, int destinationWidth, int destinationHeight)
		{
			Clipboard.SetImage(Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight));
		}

		#endregion

		#region 연속 출력

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 연속적으로 얻어낸다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 연속적으로 반환된다.</returns>
		public static IEnumerable<Bitmap> CaptureSequentially(Rectangle sourceRectangle, float ratio = 1.0f)
		{
			while (true)
			{
				int destinationWidth = (int)(sourceRectangle.Width * ratio);
				int destinationHeight = (int)(sourceRectangle.Height * ratio);

				yield return Capture(sourceRectangle, destinationWidth, destinationHeight);
			}
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 연속적으로 얻어낸다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="destinationSize">반환되는 비트맵의 크기를 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 연속적으로 반환된다.</returns>
		public static IEnumerable<Bitmap> CaptureSequentially(Rectangle sourceRectangle, Size destinationSize)
		{
			while (true)
			{
				yield return Capture(sourceRectangle, destinationSize);
			}
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 연속적으로 얻어낸다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 연속적으로 반환된다.</returns>
		public static IEnumerable<Bitmap> CaptureSequentially(Rectangle sourceRectangle, int destinationWidth, int destinationHeight)
		{
			while (true)
			{
				yield return Capture(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth > 0 ? destinationWidth : sourceRectangle.Width, destinationHeight > 0 ? destinationHeight : sourceRectangle.Height);
			}
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 얻어 낸다.
		/// </summary>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 연속적으로 반환된다.</returns>
		public static IEnumerable<Bitmap> CaptureSequentially(int sourceX, int sourceY, int sourceWidth, int sourceHeight, float ratio = 1.0f)
		{
			while (true)
			{
				int destinationWidth = (int)(sourceWidth * ratio);
				int destinationHeight = (int)(sourceHeight * ratio);

				yield return Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight);
			}
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 얻어 낸다.
		/// </summary>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 연속적으로 반환된다.</returns>
		public static IEnumerable<Bitmap> CaptureSequentially(int sourceX, int sourceY, int sourceWidth, int sourceHeight, int destinationWidth, int destinationHeight)
		{
			while (true)
			{
				yield return Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth > 0 ? destinationWidth : sourceWidth, destinationHeight > 0 ? destinationHeight : sourceHeight);
			}
		}

		#endregion

		#region 캡쳐 인터페이스(Private)

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 얻어 낸다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 반환된다.</returns>
		private static Bitmap Capture(Rectangle sourceRectangle, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceRectangle.Width * ratio);
			int destinationHeight = (int)(sourceRectangle.Height * ratio);

			return Capture(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 얻어 낸다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역의 위치와 크기를 나타내는 사각형을 설정한다.</param>
		/// <param name="destinationSize">반환되는 비트맵의 크기를 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 반환된다.</returns>
		private static Bitmap Capture(Rectangle sourceRectangle, Size destinationSize)
		{
			return Capture(sourceRectangle, destinationSize.Width, destinationSize.Height);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 얻어 낸다.
		/// </summary>
		/// <param name="sourceRectangle">캡쳐하려는 화면 영역을 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 반환된다.</returns>
		private static Bitmap Capture(Rectangle sourceRectangle, int destinationWidth, int destinationHeight)
		{
			return Capture(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, destinationWidth > 0 ? destinationWidth : sourceRectangle.Width, destinationHeight > 0 ? destinationHeight : sourceRectangle.Height);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="ratio">원본 대비 캡쳐된 비트맵의 크기 비율을 설정한다.</param>
		/// <returns></returns>
		private static Bitmap Capture(int sourceX, int sourceY, int sourceWidth, int sourceHeight, float ratio = 1.0f)
		{
			int destinationWidth = (int)(sourceWidth * ratio);
			int destinationHeight = (int)(sourceHeight * ratio);

			return Capture(sourceX, sourceY, sourceWidth, sourceHeight, destinationWidth, destinationHeight);
		}

		/// <summary>
		/// 디스플레이되고 있는 화면의 특정 영역에 대해서 이미지 스냅샷을 얻어 낸다.
		/// </summary>
		/// <param name="sourceX">캡쳐하려는 화면 영역의 좌측 상단 X 좌표를 설정한다.</param>
		/// <param name="sourceY">캡쳐하려는 화면 영역의 좌측 상단 Y 좌표를 설정한다.</param>
		/// <param name="sourceWidth">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="sourceHeight">캡쳐하려는 화면 영역의 너비를 설정한다.</param>
		/// <param name="destinationWidth">반환되는 비트맵의 너비를 설정한다.</param>
		/// <param name="destinationHeight">반환되는 비트맵의 높이를 설정한다.</param>
		/// <returns>캡쳐된 비트맵이 반환된다.</returns>
		private static Bitmap Capture(int sourceX, int sourceY, int sourceWidth, int sourceHeight,
			int destinationWidth, int destinationHeight)
		{
			Bitmap bitmap = new Bitmap(destinationWidth > 0 ? destinationWidth : sourceWidth,
				destinationHeight > 0 ? destinationHeight : sourceHeight,
				PixelFormat.Format64bppPArgb);

			Bitmap temp = new Bitmap(sourceWidth, sourceHeight, PixelFormat.Format64bppPArgb);

			using (Graphics g = Graphics.FromImage(bitmap))
			{
				try
				{
					using (Graphics graphics = Graphics.FromImage(temp))
					{
						graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

						graphics.CopyFromScreen(sourceX, sourceY, 0, 0, new Size(sourceWidth, sourceHeight));
					}

					g.DrawImage(temp, 0, 0, bitmap.Width, bitmap.Height);
				}
				finally
				{
					temp.Dispose();
				}
			}

			return bitmap;
		}

		#endregion
	}
}